home *** CD-ROM | disk | FTP | other *** search
- ;****************************************************************************
- ;*
- ;* The MegaToolbox
- ;*
- ;* Copyright (C) 1993 SciTech Software
- ;* All rights reserved.
- ;*
- ;* Filename: $RCSfile: cpu.asm $
- ;* Version: $Revision: 1.1 $
- ;*
- ;* Language: 8086 Assembler
- ;* Environment: IBM PC (MS DOS)
- ;*
- ;* Description: Autodetection routine to determine the type of CPU installed
- ;* in the system.
- ;*
- ;* $Id: cpu.asm 1.1 1993/09/02 11:04:55 kjb Exp $
- ;*
- ;****************************************************************************
-
- IDEAL
-
- INCLUDE "model.mac" ; Memory model macros
-
- header cpu ; Set up memory model
-
- ;****************************************************************************
- ;
- ; Equates used by queryCPU routine.
- ;
- ;****************************************************************************
-
- ; Central Processing Unit type codes
-
- CPU86 = 0 ; 8086/88 type processor
- CPU186 = 1 ; 80186 type processor
- CPU286 = 2 ; 80286 type processor
- CPU286p = 3 ; 80286 type processor in protected mode
- CPU386 = 4 ; 80386 type processor
- CPU386p = 5 ; 80386 type processor in protected mode
- CPU486 = 6 ; 80486 type processor
- CPU486p = 7 ; 80486 type processor in protected mode
-
- ; Floating Point Unit type codes
-
- FPUNONE = 0 ; No coprocessor present
- FPU87 = 1 ; 8087 coprocessor
- FPU287 = 2 ; 80287 coprocessor
- FPU387 = 3 ; 80387 coprocessor
- FPU487 = 4 ; 80487 coprocessor
-
- begcodeseg cpu ; Start of code segment
-
- P386 ; Enable all '386 instructions
- P387 ; Enable all '387 instructions
-
- ; Save the type of CPU detected so we can determine the co-processor
- ; type correctly. This means that we MUST call queryCpu() BEFORE calling
- ; queryFpu() to obtain correct results.
-
- cpu dw CPU86
-
- ;----------------------------------------------------------------------------
- ; cpu_type queryCpu(void)
- ;----------------------------------------------------------------------------
- ; Determine type of processor present.
- ;----------------------------------------------------------------------------
- procstart _queryCpu
-
- push bp ; We MUST save bp for initialization code...
-
- mov ax,CPU86 ; Default to 8086/8088 processor
- push sp
- pop bx ; BX holds the value of SP or SP-2
- cmp bx,sp ; 88/86/186 pushes the value of SP-2
- je @@Check286 ; Must be a 286/386/486 type processor
- mov cl,32 ; 186 uses count mod 32 = 0
- shl bx,cl ; 86 shifts 32 bits left so ax = 0
- jz @@Done ; zero: shifted out all bits so 86/88
- mov ax,CPU186 ; nonzero: no shift, so 186
- jz @@Done
-
- @@Check286: ; First check for 386/486 in 32 bit mode
- pushf ; Test for 16 or 32 operand size:
- mov bx,sp ; pushed 2 or 4 bytes of flags
- popf
- inc bx
- inc bx
- cmp bx,sp ; did pushf change sp by 2?
- jnz @@Check486 ; 32 bit push, so it is a 386/486
-
- sub sp,6 ; Is it a 286/386/486 in 16 bit mode?
- mov bp,sp
- sgdt [QWORD ptr bp] ; 80286/386/486 specific instrucion
- add sp,4 ; Get global descriptor table
- pop bx
- inc bh ; Third word of GDT = -1 for 286
- jnz @@Check486 ; We have a 386/486
-
- mov ax,CPU286 ; We have a 286
- jmp @@TestPROT
-
- @@Check486:
-
- ; Distinguish an 80386 from an 80486. Bit 18 (40000H) of EFLAGS register
- ; is used only in the 486. This code flips it and tests if anything happened.
-
- mov edx,esp ; Save stack pointer
- and esp,not 3 ; Align stack pointer to prevent a fault
- ; when we set the AC flag on a 486
- pushfd ; Copy the EFLAGS register
- pop eax ; into register eax
- mov ecx,eax ; Save the original EFLAGS value
- xor eax,40000H ; Flip the AC flag bit
- push eax ; Try to put the modified value back
- popfd ; into the EFLAGS register
- pushfd ; Copy the EFLAGS register again
- pop eax ; into eax
- xor eax,ecx ; Compare the old and new AC bits
- shr eax,18 ; Shift and mask to get the AC comparison bit
- and eax,1 ; in the low order position of eax
- push ecx
- popfd ; Restore EFLAGS that were saved on entry
- mov esp,edx ; And restore stack pointer to saved value
- mov bx,ax ; and move into bx
-
- ; At this point ax = 0 for a 386, or ax = 1 for a 486
-
- mov ax,CPU386 ; Assume a 386
- test bx,bx
- jz @@TestPROT ; We have a 386
- mov ax,CPU486 ; We have a 486
-
- @@TestPROT:
- smsw cx ; protected? machine status -> cx
- ror cx,1 ; protection bit -> carry flag
- jnc @@Done ; Real mode if no carry
- inc ax ; Protected: return value + 1
-
- @@Done:
- mov [cpu],ax ; Save CPU type in code segment variable
- pop bp ; Restore bp
- ret ; We are done
-
- procend _queryCpu
-
- ndp_cw dw ?
- ndp_sw dw ?
-
- ;----------------------------------------------------------------------------
- ; fpu_type queryFpu(void)
- ;----------------------------------------------------------------------------
- ; Determine type of floating point coprocessor present in the system.
- ; The idea is to determine whether or not the floating-point control word
- ; can be successfully read. If it cannot, then no coprocessor exists.
- ; If it can the correct coprocessor is then determined depending on the
- ; main CPU id.
- ;----------------------------------------------------------------------------
- procstart _queryFpu
-
- push bp
-
- mov bx,FPUNONE ; Default to no FPU present
-
- ; The next two 80x87 instructions cannot carry the WAIT prefix,
- ; because there may not be an 80x87 for which to wait. The WAIT is
- ; therefore emulated with a MOV CX,<value> LOOP $ combination.
-
- mov [ndp_cw],0 ; Clear the control word in memory
- cli ; Interrupts must be off during test
-
- fninit ; reset NDP status word
- mov cx,2 ; Wait for co-pro to complete operation
- loop $
-
- fnstcw [ndp_cw] ; Obtain the processor control word
- mov cx,14h ; Wait for co-pro to complete operation
- loop $
-
- sti ; Re-enable interrupts
-
- ; We check to see that the precison control bits of the control word
- ; indicate 64 bit internal precision (bits 8 & 9 set) which is the default
- ; set up by the fninit instruction above. We also test that the exception
- ; masks are properly set.
-
- mov ax,[ndp_cw] ; AX := NDP control word
- and ax,033fh ; Mask out the precision control bits etc.
- cmp ax,033fh ; is the NDP present?
- jne @@Done ; No, we are all done... (must be a 3)
-
- ; Determine the type of NDP from the main CPU type
-
- mov bx,FPU87 ; Start with the 8087 NDP
- mov ax,[cpu] ; Get current cpu type
- cmp ax,CPU286 ; >= 80286 type processor?
- jge @@80286 ; Yes, check for 287/387/487
- jmp @@Done ; No, we are done
-
- ; Now that we know we have a possible co-processor and the processor is
- ; at least an 80286, we can check to see if coprocessor emulation software
- ; is installed in the system. Some emulators such as FRANKIE.387 emulate
- ; the co-processor so well that the above checks believe a co-pro is
- ; actually out there.
-
- @@80286:
- smsw ax ; AX := machine status word
- test al,4 ; Check the EM bit status
- jnz @@Done ; Software emulation installed on INT 7!
-
- mov ax,[cpu] ; AX := current CPU flag
- cmp ax,CPU386 ; Do we have a 386 or above?
- jge @@80386 ; Yes, check for it
- mov bx,FPU287 ; We have a 80287 co-pro
- jmp @@Done
-
- @@80386:
- cmp ax,CPU486 ; Do we have a 486 or above?
- jge @@80486 ; Yes, check for it
-
- ; The i386 processor can work with either an 80287 or 80387 co processor
- ; so we must check for that here. The 387 says that +inf <> -inf while
- ; the 287 says that they are the same.
-
- fld1 ; Load +1.0 onto NDP stack
- fldz ; Load +0.0 onto NDP stack
- fdiv ; do +1/0 (create +inf)
- fld1 ; Load +1.0 onto NDP stack
- fchs ; Change to -1.0
- fldz ; Load +0.0 onto NDP stack
- fdiv ; do -1/0 (create -inf)
- fcompp ; compare and pop values from stack
- fstsw [ndp_sw] ; Get the status word from the co pro
- mov ax,[ndp_sw] ; AX := Status word
- and ah,41h ; Mask out C3 and C0 condition codes
- cmp ah,40h ; C3 = 1, C0 = 0 means ST(0) == ST(1)
- mov bx,FPU287 ; Set up for a 287 co pro
- je @@Done ; Yes, we were correct
-
- mov bx,FPU387 ; No, it was an 80387
- jmp @@Done
-
- @@80486:
- mov bx,FPU487 ; We must have a 487 co pro.
-
- @@Done:
- mov ax,bx ; Return FPU type in AX
- pop bp ; Restore bp
- ret ; We are done
-
- procend _queryFpu
-
- endcodeseg cpu
-
- END ; End of module
-